/*
 * the codes was writted by taing, but you can copy or moidfy it
 */

package com.taing.autosqlutils;

import com.taing.autosql.model.DataSqlModel;
import com.taing.autosql.service.DataSqlServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.session.Configuration;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;

/**
 * @Author tianyi
 * @Description 通过反射找到对应的dao语句
 * @Date 2023 - 01 - 31
 **/
@Slf4j
public class ServiceConfig {
    private final String NAME_SPACE = "namespace:";
    private final String FILE_EXTEND_NAME_JAVA = ".java";
    private final String FILE_EXTEND_NAME_XML = ".xml";
    private final String BEAN_NAME = "dataSqlServiceImpl";
    private final String CHARSE_NAME_UTF8 = "utf-8";

    private final Set<Class<? extends Annotation>> sqlAnnotationType = new HashSet();
    private final Set<Class<? extends Annotation>> sqlProviderAnnotationType = new HashSet();
    private Configuration configuration;
    private MapperBuilderAssistant assistant;
    private Class<?> type;

    /**
     * 构建函数
     *
     * @param configuration 配置
     * @param type          类型
     */
    public ServiceConfig(Configuration configuration, Class<?> type) {
        String resource = type.getName().replace('.', '/') + FILE_EXTEND_NAME_JAVA;
        this.assistant = new MapperBuilderAssistant(configuration, resource);
        this.configuration = configuration;
        this.type = type;
        this.sqlAnnotationType.add(Select.class);
        this.sqlAnnotationType.add(Insert.class);
        this.sqlAnnotationType.add(Update.class);
        this.sqlAnnotationType.add(Delete.class);

        this.sqlProviderAnnotationType.add(SelectProvider.class);
        this.sqlProviderAnnotationType.add(InsertProvider.class);
        this.sqlProviderAnnotationType.add(UpdateProvider.class);
        this.sqlProviderAnnotationType.add(DeleteProvider.class);

    }

    public void parse(String methodName) {
        String resource = this.type.toString();
        if (!this.configuration.isResourceLoaded(resource)) {
            // load xml file by method name

            DataSqlServiceImpl dataSqlServiceImpl = SpringUtils.getBean(BEAN_NAME);
            loadXmlResource(methodName, dataSqlServiceImpl);
        }
    }

    private void loadXmlResource(String methodName, DataSqlServiceImpl dataSqlServiceImpl) {
        if (!this.configuration.isResourceLoaded(NAME_SPACE + this.type.getName())) {
            String xmlResource = this.type.getName().replace('.', '/') + FILE_EXTEND_NAME_XML;
            String sSql = getSerivceConfigApi(methodName, dataSqlServiceImpl);
            if (sSql.trim().length() > 0) {
                ByteArrayInputStream inputStream = null;
                try {
                    inputStream = new ByteArrayInputStream(sSql.getBytes(CHARSE_NAME_UTF8));
                } catch (UnsupportedEncodingException e) {
                    log.error("sql is not correct, please check it");
                    throw new RuntimeException("sql is not correct, please check it");
                }
                if (inputStream != null) {
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(inputStream, this.assistant.getConfiguration(),
                            xmlResource, this.configuration.getSqlFragments(),
                            this.type.getName());
                    xmlMapperBuilder.parse();
                }
            } else {
                String msg = "there is not sql related the method key=" + methodName;
                log.error(msg);
            }
        }
    }

    private String getSerivceConfigApi(String methodName, DataSqlServiceImpl dataSqlServiceImpl) {
        DataSqlModel dataSqlModel = dataSqlServiceImpl.findDataSqlByMethod(methodName);
        return dataSqlModel.getSqlContext();
    }

}
